<?php

namespace common\service;

use common\exception\LogicException;
use common\model\OrderModel;
use common\model\OrderTaskListModel;
use common\model\TaskModel;
use common\model\TaskRelationModel;
use common\model\TaskUpstreamTransModel;
use support\ErrorCode;
use support\SingletonTrait;
use think\Exception;

class TaskUpstreamTransService
{
    use SingletonTrait;

    public function __construct()
    {
    }

    /**
     * 给任务创建下载状态
     */
    public function saveTaskTrans($data)
    {
        $res = [];
        if (empty($data['from_task_id']) || empty($data['to_task_id'])) {
            return false;
        }
        $taskList = model(TaskModel::class)
            ->where(['id' => ['in', [$data['from_task_id'], $data['to_task_id']]]])
            ->field('id, project_id, tenant_id')
            ->select();
        $taskMap = array_column($taskList, null, 'id');
        if (count($taskList) < 2) {
            return false;
        }
        $transRecord = model(TaskUpstreamTransModel::class)
            ->where([
                'from_task_id' => $data['from_task_id'],
                'to_task_id' => $data['to_task_id'],
            ])
            ->find();
        $saveData = [];
        $checkKeyList = [
            "status",
            "is_unzip",
            "is_assemble",
        ];
        foreach ($checkKeyList as $key) {
            if (isset($data[$key])) {
                $saveData[$key] = $data[$key];
            }
        }

        if (empty($transRecord)) {
            $saveData = array_merge($saveData, [
                'from_task_id' => $data['from_task_id'],
                'to_task_id' => $data['to_task_id'],
                'from_project_id' => $taskMap[$data['from_task_id']]['project_id'],
                'to_project_id' => $taskMap[$data['to_task_id']]['project_id'],
                'from_tenant_id' => $taskMap[$data['from_task_id']]['tenant_id'],
                'to_tenant_id' => $taskMap[$data['to_task_id']]['tenant_id'],
            ]);
            if (in_array($data['status'] ?? '', TaskUpstreamTransModel::STATUS_GROUP_DONE)) {
                $saveData['download_at'] = time();
            }
            $res = model(TaskUpstreamTransModel::class)->addItem($saveData);
        } else {
            $saveData['id'] = $transRecord['id'];
            if (in_array($data['status'] ?? '', TaskUpstreamTransModel::STATUS_GROUP_DONE)
                && in_array($transRecord['status'], TaskUpstreamTransModel::STATUS_GROUP_WAIT)
            ) {
                $saveData['download_at'] = time();
            }
            $res = model(TaskUpstreamTransModel::class)->save($saveData);
        }
        return $res;
    }

    /**
     * 获取任务的task_relation关联任务
     * @param array  $taskIdList
     * @param string $direction
     * @return mixed|void
     */
    public function getTaskRelationTask(array $taskIdList, string $direction = "upstream")
    {
        if (empty($taskIdList)) {
            return [];
        }
        $currentKey = $direction == "upstream" ? "source_task_id" : "target_task_id";
        $taskProjectList = model(TaskModel::class)
            ->where(['id' => ['in', $taskIdList]])
            ->field('id, project_id')
            ->select();
        $taskProjectList = array_group_by($taskProjectList, 'project_id');
        $res = [];
        foreach ($taskProjectList as $projectId => $taskList) {
            $temp = model(TaskRelationModel::class)
                ->setSuffix(sprintf('_project_%d', $projectId))
                ->where([
                    'relation_type' => ['in', ['entity', 'episode', 'upstream']],
                    $currentKey => ['in', array_column($taskList, 'id')]
                ])
                ->field('source_task_id,target_task_id')
                ->select();
            $res = array_merge($res, $temp);
        }
        return $res;
    }

    /**
     * 查询任务的上游（或下游）任务传输状态
     * @param array  $taskIdList
     * @param string $direction
     * @param string $type
     * @return array
     */
    public function getTransByTaskIdList(array $taskIdList, string $direction = 'upstream', string $type = "normal"): array
    {
        $res = [];
        $taskIdListExtended = [];
        $orderTaskIdMap = [];
        $orderTaskIdReturnMap = [];

        if ($direction == "upstream") {
            // 查上游则自己是乙方
            $orderSelfKey = "real_task_id";
            $orderPartnerKey = "task_id";
        } else {
            // 查下游则自己是甲方
            $orderSelfKey = "task_id";
            $orderPartnerKey = "real_task_id";
        }

        if (in_array($type, ["all", "order_all", "order"])) {
            // 填充订单任务上游
            $orderTaskIdList = model(OrderModel::class)
                ->join("order_task_list otl on order.id = otl.order_id")
                ->where([
                    ("otl." . $orderSelfKey) => ["in", $taskIdList],
                    "otl.status" => ["eq", "default"],
                ])
                ->field("otl.task_id, otl.real_task_id")
                ->select();
            $taskIdListExtended = array_column($orderTaskIdList, 'task_id');
            $orderTaskIdMap = array_column($orderTaskIdList, $orderSelfKey, $orderPartnerKey);
        }

        $taskIdListExtended = array_merge($taskIdListExtended, $taskIdList);
        // 获取任务的task_relation上游任务
        $taskUpstreamList = $this->getTaskRelationTask($taskIdListExtended, $direction);

        if (in_array($type, ["all", "order_all", "order_return"])) {
            // 填充订单回收上下游
            $orderTaskIdList = model(OrderModel::class)
                ->join("order_task_list otl on order.id = otl.order_id")
                ->where([
                    ("otl." . $orderPartnerKey) => ["in", $taskIdList],
                    "otl.status" => ["eq", "default"],
                ])
                ->field("otl.task_id, otl.real_task_id")
                ->select();
            foreach ($orderTaskIdList as $item) {
                $taskUpstreamList[] = [
                    'source_task_id' => $item['task_id'],
                    'target_task_id' => $item['real_task_id'],
                ];
            }
            $orderTaskIdReturnMap = array_column($orderTaskIdList, $orderSelfKey, $orderPartnerKey);
        }

        if (empty($taskUpstreamList)) {
            return $res;
        }
        // 取出所有任务id以判断跨项目与否
        $allTaskIds = array_unique(array_merge(
            array_column($taskUpstreamList, 'source_task_id'),
            array_column($taskUpstreamList, 'target_task_id')
        ));
        $taskInfoList = model(TaskModel::class)
            ->where(['id' => ['in', $allTaskIds]])
            ->field('id, project_id')
            ->select();
        $taskInfoMap = array_column($taskInfoList, 'project_id', 'id');

        $targetKey = $direction == "upstream" ? "source_task_id" : "target_task_id";
        $taskUpstreamGrouped = array_group_by($taskUpstreamList, $targetKey);

        // 获取现有传输数据
        $transList = model(TaskUpstreamTransModel::class)
            ->where([
                'from_task_id' => ['in', array_column($taskUpstreamList, 'target_task_id')],
                'to_task_id' => ['in', array_column($taskUpstreamList, 'source_task_id')],
            ])
            ->select();

        $transListMap = [];
        $sourceKey = $direction == "upstream" ? "from_task_id" : "to_task_id";
        $targetKey = $direction == "upstream" ? "to_task_id" : "from_task_id";
        foreach ($transList as $item) {
            $transListMap[$item[$targetKey]][$item[$sourceKey]] = $item;
        }
        // 填充缺失传输数据
        $sourceKey = $direction == "upstream" ? "target_task_id" : "source_task_id";
        $nextKey = $direction == "upstream" ? "from_task_id" : "to_task_id";
        foreach ($taskUpstreamGrouped as $currentTaskId => $upstreamList) {
            $type = "normal";
            if (isset($orderTaskIdMap[$currentTaskId])) {
                // 订单任务转换为真实的接包任务
                $currentTaskId = $orderTaskIdMap[$currentTaskId];
                $type = "outsource";
            }
            $taskTrans = [];
            $upstreamIdList = array_column($upstreamList, $sourceKey);
            foreach ($upstreamIdList as $upstreamId) {
                $currentType = $type;
                if (isset($orderTaskIdReturnMap[$currentTaskId]) && $orderTaskIdReturnMap[$currentTaskId] == $upstreamId) {
                    // 在订单回传列表内
                    $currentType = $direction == "upstream" ? "outsource_return" : "outsource_upload";
                } else if ($taskInfoMap[$currentTaskId] != $taskInfoMap[$upstreamId]) {
                    // 其他跨租户关系
                    $currentType = "outsource";
                }
                $taskTrans[$upstreamId] = [
                    $nextKey => $upstreamId,
                    "status" => "wait_upload",
                    "is_unzip" => "no",
                    "is_assemble" => "no",
                    "type" => $currentType,
                ];
                if (!isset($transListMap[$currentTaskId][$upstreamId])) {
                    continue;
                }
                $taskTrans[$upstreamId] = array_replace($taskTrans[$upstreamId], [
                    'status' => $transListMap[$currentTaskId][$upstreamId]['status'],
                    'is_unzip' => $transListMap[$currentTaskId][$upstreamId]['is_unzip'],
                    'is_assemble' => $transListMap[$currentTaskId][$upstreamId]['is_assemble'],
                ]);
            }
            if (!isset($res[$currentTaskId])) {
                $res[$currentTaskId] = [
                    'task_id' => $currentTaskId,
                    'trans_list' => array_values($taskTrans),
                ];
            } else {
                $res[$currentTaskId]['trans_list'] = array_merge($res[$currentTaskId]['trans_list'], array_values($taskTrans));
            }
        }
        return array_values($res);
    }


    /**
     * 订单身份打组
     * @param array $orderIdList
     * @param int   $tenantId
     * @return array
     */
    public function getOrderIdentityMapByOrderIdList(array $orderIdList = [], int $tenantId = 0): array
    {
        $res = [];
        if (empty($tenantId)) {
            $tenantId = \request()->getTenantId();
        }
        $orderFilter = [
            [
                "from_tenant_id" => $tenantId,
                "to_tenant_id" => $tenantId,
                "_logic" => "or",
            ]
        ];
        if (!empty($orderIdList)) {
            $orderFilter = ["id" => ["in", $orderIdList]];
        }

        $orderList = model(OrderModel::class)
            ->where($orderFilter)
            ->field("id, status, from_tenant_id, to_tenant_id")
            ->order("id desc")
            ->select();
        foreach ($orderList as $order) {
            switch ($tenantId) {
                case $order['from_tenant_id']:
                    $res[$order['id']] = "partyA";
                    break;
                case $order['to_tenant_id']:
                    $res[$order['id']] = "partyB";
                    break;
                default:
                    continue 2;
            }
        }
        return $res;
    }

    /**
     * 获取订单任务的传输详情
     * @param array  $allOrderIdList
     * @param string $transType
     * @return array
     */
    public function getTransByOrderId(array $allOrderIdList = [], string $transType = "download"): array
    {
        $res = [];

        // 整理订单身份map
        $orderRoleMap = $this->getOrderIdentityMapByOrderIdList($allOrderIdList);
        $orderIdList = array_keys($orderRoleMap);

        $orderTaskTrans = [];

        // 订单任务打组
        $orderTaskList = model(OrderTaskListModel::class)
            ->where([
                "order_id" => ["in", $orderIdList],
                "status" => "default",
            ])
            ->field("order_id, task_id, real_task_id")
            ->select();
        if (empty($orderTaskList)) {
            return $res;
        }
        $orderTaskListGrouped = array_group_by($orderTaskList, "order_id");
        foreach ($orderTaskListGrouped as $orderId => $list) {
            $direction = ($orderRoleMap[$orderId] == "partyA" xor $transType == "download") ? "upstream" : "downstream";
            $taskIdList = array_column($list, 'real_task_id');
            $orderTaskTrans[$orderId]['trans_list'] = $this->getTransByTaskIdList($taskIdList, $direction, "order_all");
        }
        foreach ($orderTaskTrans as $orderId => $transItem) {
            $transItem['order_id'] = $orderId;
            $res[] = $transItem;
        }
        return $res;
    }

    /**
     * 我的订单任务，上游传输状态查询
     * @param array $page
     * @param array $projectIds
     * @param array $episodeCodes
     * @return array
     */
    public function getMyOrderTaskTrans(array $page = [], array $projectIds = [], array $episodeCodes = [], string $taskName = "")
    {
        $res = [];
        $onlyOrderId = ($param["only_order_id"] ?? "no") == "yes";
        $currentTenantId = \request()->getTenantId();

        // 查询我的任务ids
        $taskStatusList = StatusService::getInstance()->byCodeMap(['closed'], true, 'id');
        $filter = [
            'task.executor' => \request()->getUserId(),
            'task.json->>"$.task_status"' => ["in", $taskStatusList]
        ];
        if (!empty($projectIds)) {
            $filter['task.project_id'] = ['in', $projectIds];
        }
        if (!empty($episodeCodes)) {
            $filter['entity.initial_episode_code'] = ['in', $episodeCodes];
        }
        if (!empty($taskName)) {
            $filter['task.name'] = ['like', '%' . $taskName . '%'];
        }
        $myTaskIdList = model(TaskModel::class)
            ->join('entity on entity.id = task.entity_id')
            ->where($filter)
            ->field('task.id')
            ->select();
        $myTaskIdList = array_column($myTaskIdList, 'id');
        if (empty($myTaskIdList)) {
            return $res;
        }
        // 查询订单任务
        if (empty($page)) {
            $page = [1, C('default_page_total')];
        }
        $orderTaskInfo = model(OrderTaskListModel::class)
            ->join('`order` on `order`.id = order_task_list.order_id')
            ->join('project on `order`.project_id = project.id')
            ->join('task on task.id = order_task_list.task_id')
            ->join('entity on entity.id = task.entity_id')
            ->where([
                [
                    'order_task_list.task_id' => ['in', $myTaskIdList],
                    'order_task_list.real_task_id' => ['in', $myTaskIdList],
                    '_logic' => 'or',
                ],
                '`order`.status' => 'inprogress',
                'order_task_list.status' => 'default',
            ])
            ->field('`order`.id as order_id, `order`.from_tenant_id, order.number, `order`.param->>"$.company_name" as company_name, `order`.param->>"$.step_category_name" as step_category_name, project.name as project_name, entity.initial_episode_code as episode_code, order_task_list.task_id, order_task_list.real_task_id')
            ->page(...$page)
            ->select();
        // 获取订单map
        // 获得上游关系
        $orderMap = [];
        $needQueryUpstreamList = [];
        $fromTaskList = [];
        $toTaskList = [];
        foreach ($orderTaskInfo as $item) {
            if (!isset($orderMap[$item['order_id']])) {
                $orderMap[$item['order_id']] = [
                    'project_name' => $item['project_name'],
                    'step_category_name' => $item['step_category_name'],
                    'from_tenant_id' => $item['from_tenant_id'],
                    'number' => $item['number'] ?? 0,
                    'company_name' => $item['company_name'] ?? 'default',
                ];
            }
            $orderMap[$item['order_id']]['episode_code_list'][$item['episode_code']] = $item['episode_code'];
            $needQueryUpstreamList[] = $item['task_id'];
            $fromTaskList[] = $item['real_task_id'];
            $toTaskList[] = $item['task_id'];
            $toTaskList[] = $item['real_task_id'];
        }
        $upstreamList = $this->getTaskRelationTask($needQueryUpstreamList, "upstream");
        $upstreamMap = [];
        foreach ($upstreamList as $item) {
            $upstreamMap[$item['source_task_id']][] = $item['target_task_id'];
        }

        $fromTaskList = array_merge(
            $fromTaskList,
            array_column($upstreamList, 'target_task_id')
        );

        if (empty($toTaskList)) {
            return [];
        }
        $filterIdList = [
            'from_task_id' => ['in', $fromTaskList],
            'to_task_id' => ['in', $toTaskList],
            'status' => ['in', TaskUpstreamTransModel::STATUS_GROUP_WAIT]
        ];
        $taskTransList = model(TaskUpstreamTransModel::class)
            ->where($filterIdList)
            ->field('from_task_id,to_task_id,status')
            ->select();
        $taskTransMap = [];
        foreach ($taskTransList as $item) {
            $taskTransMap[$item['from_task_id']][$item['to_task_id']] = $item['status'];
        }
        // 按订单分组
        $orderTransMap = [];
        foreach ($orderTaskInfo as $item) {
            // 甲方上传: 我的上游->乙方
            // 乙方下载: 甲方的上游->我
            foreach ($upstreamMap[$item['task_id']] ?? [] as $upstreamId) {
                $transItem = [
                    'from' => $upstreamId,
                    'to' => $item['real_task_id'],
                    'type' => in_array($item['task_id'], $myTaskIdList) ? 'upload' : 'download',
                    'status' => $taskTransMap[$upstreamId][$item['real_task_id']] ?? TaskUpstreamTransModel::STATUS_WAIT_UPLOAD,
                ];
                $orderTransMap[$item['order_id']][] = $transItem;
            }
            // 乙方上传: 我->甲方
            // 甲方下载： 乙方->我
            $transItem = [
                'from' => $item['real_task_id'],
                'to' => $item['task_id'],
                'type' => in_array($item['task_id'], $myTaskIdList) ? 'download' : 'upload',
                'status' => $taskTransMap[$item['real_task_id']][$item['task_id']] ?? TaskUpstreamTransModel::STATUS_WAIT_UPLOAD,
            ];
            $orderTransMap[$item['order_id']][] = $transItem;
        }
        // 组织订单状态统计
        foreach ($orderTransMap as $orderId => $list) {
            $orderCount = [
                'order_id' => $orderId,
                'project_name' => $orderMap[$orderId]['project_name'],
                'step_category_name' => $orderMap[$orderId]['step_category_name'],
                'number' => $orderMap[$orderId]['number'],
                'company_name' => $orderMap[$orderId]['company_name'],
                'order_party_type' => ($currentTenantId == $orderMap[$orderId]['from_tenant_id']) ? 'party_a' : 'party_b',
                'episode_code_list' => array_values($orderMap[$orderId]['episode_code_list']),
                TaskUpstreamTransModel::STATUS_WAIT_UPLOAD => 0,
                TaskUpstreamTransModel::STATUS_WAIT_DOWNLOAD => 0,
                TaskUpstreamTransModel::STATUS_WAIT_UPDATE => 0,
            ];
            $isSkip = true;
            foreach ($list as $listItem) {
                if ($listItem['type'] == 'upload' && $listItem['status'] !== TaskUpstreamTransModel::STATUS_WAIT_UPLOAD) {
                    continue;
                }
                if ($listItem['type'] == 'download' && !in_array($listItem['status'], [
                        TaskUpstreamTransModel::STATUS_WAIT_DOWNLOAD,
                        TaskUpstreamTransModel::STATUS_WAIT_UPDATE
                    ])) {
                    continue;
                }
                $isSkip = false;
                $orderCount[$listItem['status']] += 1;
            }
            if (!$isSkip) {
                if ($onlyOrderId) {
                    $res[] = [
                        'order_id' => $orderId,
                    ];
                } else {
                    $res[] = $orderCount;
                }
            }
        }
        return $res;
    }
}
